package com.kgc.scd.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.kgc.scd.bean.User;
import com.kgc.scd.bean.Vip;
import com.kgc.scd.bean.VipExample;
import com.kgc.scd.config.WechatPayConfig;
import com.kgc.scd.contant.WechatPayConstant;
import com.kgc.scd.mapper.Usermapper;
import com.kgc.scd.mapper.Vipmapper;
import com.kgc.scd.service.WechatPayService;
import com.kgc.scd.util.DateUtil;
import com.kgc.scd.util.HttpClient4Util;
import com.kgc.scd.util.WechatPayUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Map;
import java.util.TreeMap;

/**
 * Created On : 2022/5/31.
 * <p>
 * Author : zhukang
 * <p>
 * Description: 微信支付业务接口实现类
 */
@Service
@Slf4j
public class WechatPayServiceImpl implements WechatPayService {

    @Autowired
    private WechatPayConfig wechatPayConfig;

    @Autowired(required = false)
    private Usermapper usermapper;

    @Autowired(required = false)
    private Vipmapper vipmapper;

    @Override
    public String wechatPayUnifiedOrderParamsXml(String body, int totalFee, String prodId, String vipOrderId, String userId) throws Exception{

        // 微信官方接口集合参数要求：非空参数值的参数按照参数名ASCII码从小到大排序（字典序），参数名区分大小写，sign参数不参与签名
        // 定义微信官方统一下单参数集合，要求根据参数名字典序排序，可选择集合：TreeMap，自动根据key进行自然排序
        Map<String, String> paramsMap = new TreeMap<>();

        // 公众账号ID
        paramsMap.put("appid", wechatPayConfig.getAppId());

        // 商户号
        paramsMap.put("mch_id", wechatPayConfig.getMchId());

        // 设备号,PC网页或公众号内支付可以传"WEB"
        paramsMap.put("device_info", "WEB");

        // 随机字符串,长度要求在32位以内,增加签名的安全性
        paramsMap.put("nonce_str", WechatPayUtil.generateNonceStrUseRandom());

        // 商品描述
        paramsMap.put("body", body);

        // 商品详情，商品详细描述，对于使用单品优惠的商户，该字段必须按照规范上传，商品信息的json字符串，从数据库查询的商品信息

        // 附加数据
        paramsMap.put("attach", userId);

        // 商户订单号，商户系统内部订单号，要求32个字符内（最少6个字符），只能是数字、大小写字母_-|*且在同一个商户号下唯一
        paramsMap.put("out_trade_no", vipOrderId);

        // 标价金额，单位是分
        paramsMap.put("total_fee", String.valueOf(totalFee));

        // 终端IP，用户的客户端IP，服务器的ip
        paramsMap.put("spbill_create_ip", "127.0.0.1");

        // 通知地址，异步接收微信支付结果通知的回调地址，通知url必须为外网可访问的url，不能携带参数。使用内网穿透
        paramsMap.put("notify_url", wechatPayConfig.getNotifyUri());

        // 交易类型，NATIVE - Native支付，PC端
        paramsMap.put("trade_type", WechatPayConstant.WECHAT_PAY_TRADE_TYPE_NATIVE);

        // 商品ID，trade_type=NATIVE时，此参数必传。此参数为二维码中包含的商品ID，商户自行定义。
        paramsMap.put("product_id", prodId);

        // 生成签名，sign参数不参与签名，作为接口参数，传递签名的结果
        // 一般情况，都是将所有的签名参数确定后，最后进行签名处理，将签名后的sign放入参数接口，返回
        paramsMap.put("sign", WechatPayUtil.generateSignature(paramsMap, wechatPayConfig.getMchKey()));

        // 接口参数要转为xml格式字符串返回
        return WechatPayUtil.generateParamsStrMapToXml(paramsMap);
    }

    @Override
    public Map<String, String> wechatPayUnifiedOrder(String unifiedOrderParamsXml) throws Exception {

        // 内部发情http请求，到微信官方进行统一下预支付订单，必须使用post请求，同步返回一个下单结果字符串，xml格式
        String unifiedOrderResultXml = HttpClient4Util.getResponse4PostByString(wechatPayConfig.getOrderUri(), unifiedOrderParamsXml, WechatPayConstant.WECHAT_PAY_ENCODING_UTF8);

        // 统一下预支付订单，结果转换为map集合，返回
        return WechatPayUtil.generateResultMapUseXmlToMap(unifiedOrderResultXml);
    }

    @Override
    public String wechatPayNotifyResultResolve(String wxpayNotifyResultXml) throws Exception {

        // 将微信官方异步回调结果，转换为map集合
        Map<String, String> wxpayNotifyResultMap = WechatPayUtil.generateResultMapUseXmlToMap(wxpayNotifyResultXml);

        log.info("微信官方异步回调结果:{}", wxpayNotifyResultMap);

        // 解析成功结果
        if (WechatPayConstant.WECHAT_PAY_SUCCESS.equals(wxpayNotifyResultMap.get("return_code"))){
            log.info("解析成功-------");
            // 进行签名校验，商户系统对于支付结果通知的内容一定要做签名验证,并校验返回的订单金额是否与商户侧的订单金额一致，防止数据泄露导致出现“假通知”，造成资金损失。
            if(WechatPayUtil.isSignatureValid(wxpayNotifyResultMap, wechatPayConfig.getMchKey())){
                log.info("签名校验成功");
                // 签名成功，响应是可信的，且正确
                // TODO 业务处理，比如：修改订单状态，给用户加积分等

                QueryWrapper<User> wrapper = new QueryWrapper<>();
                wrapper.eq("user_id",wxpayNotifyResultMap.get("attach"));
                User user = usermapper.selectOne(wrapper);
                log.info("user:----{}", user);
                if (user.getUserVipid() == 0){
                    Vip vip = Vip.builder()
                            .userId(user.getUserId())
                            .vipLevel(1)
                            .expiretime(DateUtil.checkTimePast(new Date(),30))
                            .build();
                    log.info("-------vip:{}",vip);
                    vipmapper.insertSelective(vip);
                    User newUser = User.builder()
                            .userId(user.getUserId())
                            .userVipid(vip.getVipId()).build();
                    log.info("-------newUser:{}",newUser);
                    usermapper.updateByPrimaryKeySelective(newUser);
                } else{
                    VipExample vipExample = new VipExample();
                    VipExample.Criteria criteria = vipExample.createCriteria();
                    criteria.andUserIdEqualTo(user.getUserId());
                    Vip vip = vipmapper.selectByExample(vipExample).get(0);
                    Vip newVip = Vip.builder()
                            .vipId(vip.getVipId())
                            .userId(user.getUserId())
                            .vipLevel(vip.getVipLevel() + 1)
                            .expiretime(DateUtil.checkTimePast(vip.getExpiretime(),30))
                            .build();
                    log.info("------ vip:{}",vip);
                    vipmapper.updateByPrimaryKeySelective(newVip);
                }
                // 响应微信官方成功
                log.info("响应微信官方成功");
                return WechatPayConstant.WECHAT_PAY_NOTIFY_RESULT_RESPONSE_SUCCESS;
            }
        }
        log.info("响应微信官方失败");
        // 响应微信官方失败
        return WechatPayConstant.WECHAT_PAY_NOTIFY_RESULT_RESPONSE_FAIL;
    }
}
